// 编译时优化的卷积核
template <int KernelSize, typename T = float>
class ConvolutionKernel
{
    T kernel_[KernelSize][KernelSize];

public:
    // 编译时索引检查
    template <int I, int J>
    constexpr T get() const
    {
        static_assert(I >= 0 && I < KernelSize, "I out of bounds");
        static_assert(J >= 0 && J < KernelSize, "J out of bounds");
        return kernel_[I][J];
    }

    // 运行时索引访问
    T get(int i, int j) const
    {
        assert(i >= 0 && i < KernelSize);
        assert(j >= 0 && j < KernelSize);
        return kernel_[i][j];
    }

    // 编译时展开的卷积操作
    template <typename ImageT>
    void apply(const ImageT &input, ImageT &output) const
    {
        constexpr int half = KernelSize / 2;

        for (int y = half; y < input.height() - half; ++y)
        {
            for (int x = half; x < input.width() - half; ++x)
            {
                T sum = 0;

                // 编译时展开循环
                // 编译期间决策选用哪段代码：减少for loop的损失
                if constexpr (KernelSize == 3)
                {
                    sum += input.at(y - 1, x - 1) * kernel_[0][0];
                    sum += input.at(y - 1, x) * kernel_[0][1];
                    sum += input.at(y - 1, x + 1) * kernel_[0][2];
                    sum += input.at(y, x - 1) * kernel_[1][0];
                    sum += input.at(y, x) * kernel_[1][1];
                    sum += input.at(y, x + 1) * kernel_[1][2];
                    sum += input.at(y + 1, x - 1) * kernel_[2][0];
                    sum += input.at(y + 1, x) * kernel_[2][1];
                    sum += input.at(y + 1, x + 1) * kernel_[2][2];
                }
                else
                {
                    // 通用实现
                    for (int ky = 0; ky < KernelSize; ++ky)
                    {
                        for (int kx = 0; kx < KernelSize; ++kx)
                        {
                            sum += input.at(y + ky - half, x + kx - half) * kernel_[ky][kx];
                        }
                    }
                }

                output.at(y, x) = sum;
            }
        }
    }
};